#if !defined(ximera_input_iinputsystem_hpp)
#define ximera_input_iinputsystem_hpp

// -----------------------------------------------------------

#include <ximera/types.hpp>
#include <ximera/common/sharedptr.hpp>
#include <ximera/enum.hpp>
#include <ximera/common/signal.hpp>
#include <ximera/system/isystem.hpp>
#include <ximera/input/idevice.hpp>
#include <ximera/input/ikeyboard.hpp>
#include <ximera/input/imouse.hpp>

namespace ximera { namespace input
{
    //! \brief Exception for Input System errors
    XIMERA_DECLARE_EXCEPTION_SUB(InputSystemException, system::SystemException, L"Input System error");

    //! \brief Types of devices that can be used with the IInputSystem.
    XIMERA_ENUM(DeviceType)
        Keyboard = 0,   //!< A Keyboard device
        Mouse,      //!< A Mouse device
        Player1,    //!< A Gamepad, Joystick or other device
        Player2,    //!< A Gamepad, Joystick or other device
        Player3,    //!< A Gamepad, Joystick or other device
        Player4,    //!< A Gamepad, Joystick or other device
        Player5,    //!< A Gamepad, Joystick or other device
        Player6,    //!< A Gamepad, Joystick or other device
        Player7,    //!< A Gamepad, Joystick or other device
        Player8     //!< A Gamepad, Joystick or other device
    XIMERA_ENUM_END(DeviceType)
    
    /*! \brief Interface that will be used to handle input of the keyboard, mouse and/or gamepads.
     * 
     * The class that implements this interface will have to be able to detect when a device was 
     * disconnected or connected to the system. When detecting a connection/disconnection the class 
     * will have to call to the event #onConnectDevice or #onDisconnectDevice, depending on the case.
     */
    class XIMERA_API IInputSystem : public system::ISystem
    {
    public:
        /*! Defines the prototype of the event that will be called when a device is connected to the system.
         *  \param device Is the device that was connected 
         */
        typedef void (OnConnectDeviceEvent)(SharedPtr<IDevice>& device);

        /*! Defines the prototype of the event that will be called when a device is disconnected from the system.
         *  \param device Is the device that was disconnected 
         */
        typedef void (OnDisconnectDeviceEvent)(SharedPtr<IDevice>& device);

        virtual ~IInputSystem();

        /*! Called to update the status of the input system. */
        virtual void update() = 0;

        /*! Returns a SharedPtr to a IDevice interface.
            \param deviceType The type of device that is wanted. */
        virtual SharedPtr<IDevice> device(DeviceType const& deviceType) = 0;

        /*! Returns a SharedPtr to a IKeyboard interface. */
        virtual SharedPtr<IKeyboard> keyboard() = 0;

        /*! Returns a SharedPtr to a IMouse interface. */
        virtual SharedPtr<IMouse> mouse() = 0;

        /*! Event that rises when a device is connected to the system. */
        Signal<OnConnectDeviceEvent>& onConnectDevice();

        /*! Event that rises when a device is disconnected from the system. */
        Signal<OnDisconnectDeviceEvent>& onDisconnectDevice();

    private:
        Signal<OnConnectDeviceEvent> _onConnectDevice;
        Signal<OnDisconnectDeviceEvent> _onDisconnectDevice;
    };
}}

// -----------------------------------------------------------

#endif